package com.xinou.daily_report.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.xinou.common.base.database.BasePO;
import com.xinou.daily_report.PO.FruitUrgePO;
import com.xinou.daily_report.VO.fruit.FruitCountVO;
import com.xinou.daily_report.VO.fruit.FruitListVO;
import com.xinou.daily_report.VO.integral.IntegralCountVO;
import com.xinou.daily_report.entity.*;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinou.common.base.config.ApiResponse;
import com.xinou.common.base.exception.BusException;
import com.xinou.common.enumerate.HttpStatusEnum;
import com.xinou.common.util.BeanUtil;
import com.xinou.daily_report.PO.FruitPO;
import com.xinou.daily_report.VO.fruit.FruitInfoVO;
import com.xinou.daily_report.enumerate.SysConfigEnum;
import com.xinou.daily_report.mapper.SysFruitMapper;
import com.xinou.daily_report.service.*;
import com.xinou.daily_report.utils.ConstUtil;
import com.xinou.daily_report.utils.DailyShiroUtil;
import com.xinou.sso.dto.UserRoleDTO;
import com.xinou.sso.mapper.SysUserMapper;
import com.xinou.sso.service.SysUserService;
import com.xinou.sso.vo.user.UserListVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.jni.Local;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import com.xinou.daily_report.service.SysFruitService;
import com.xinou.daily_report.service.SysWeekResultService;
import com.xinou.daily_report.service.SysWeekTimeService;
import com.xinou.sso.util.ShiroUtil;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author lizhongyuan
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SysFruitServiceImpl extends ServiceImpl<SysFruitMapper, SysFruit> implements SysFruitService {

    private final SysUserService sysUserService;
    private final SysWeekResultService sysWeekResultService;
    private final SysWeekTimeService sysWeekTimeService;
    private final SysDailyCommentService sysDailyCommentService;
    private final SysUserMapper sysUserMapper;
    private final SysOkFormService sysOkFormService;
    private final SysDailyService sysDailyService;
    private final SysCalendarService sysCalendarService;


    @Override
    public ApiResponse<FruitListVO> fruitList(FruitPO po) {
        Page<SysFruit> page = new Page<>(po.getPageNumber(), po.getPageSize());
        return new ApiResponse<>(this.baseMapper.fruitList(page, po));
    }

    @Override
    public ApiResponse<FruitCountVO> fruitCount(FruitPO po) {
        FruitCountVO vo = new FruitCountVO();
        Map<Integer, BigDecimal> info = this.baseMapper.fruitCount(po)
                .stream()
                .collect(Collectors.toMap(FruitCountVO::getType, FruitCountVO::getSum,(k1, k2) -> k1));
        vo.setInfo(info);
        return new ApiResponse<>(vo);
    }

    @Override
    public ApiResponse<Void> fruitSave(FruitPO po) {
        if(po.getReason().length()>200){
            throw new BusException(HttpStatusEnum.RE_CODE_DATABASE_ERROR,"添加水果基金失败,原因长度过长");
        }
        po.setInsertTime(LocalDateTime.now());
        if (po.getCommanderId() == null) {
            po.setCommanderId(ShiroUtil.getUserId());
        }
        boolean flag = save(BeanUtil.beanA2beanB(po,SysFruit.class));
        if(!flag){
            throw new BusException(HttpStatusEnum.RE_CODE_DATABASE_ERROR,"添加水果基金失败");
        }
        return new ApiResponse<>();
    }

    @Override
    public ApiResponse<FruitInfoVO> fruitGetById(FruitPO fruitPO) {
        return new ApiResponse<FruitInfoVO>(BeanUtil.beanA2beanB(getById(fruitPO.getId()), FruitInfoVO.class));
    }

    @Override
    public ApiResponse<Void> fruitConfirmById(FruitPO fruitPO) {
        //key为id，值为sysFrui
        Map<Long, SysFruit> sysFruitMap = list().stream().collect(Collectors.toMap(SysFruit::getId, SysFruit -> SysFruit));
        ArrayList<SysFruit> sysFruits = new ArrayList<>();
        if (fruitPO.getId() != null){
            SysFruit byId = getById(fruitPO.getId());
            byId.setState(1);
            sysFruits.add(byId);
        }else if (fruitPO.getIds().size() > 0){
            for (Long id : fruitPO.getIds()) {
                SysFruit byId = sysFruitMap.get(id);
                byId.setState(1);
                sysFruits.add(byId);
//                updateById(byId);
            }
        }else {
            throw new BusException(HttpStatusEnum.RE_CODE_DATABASE_ERROR,"确认水果基金失败，请选择指定的人后重试");
        }
        boolean flag = updateBatchById(sysFruits);
        return new ApiResponse<>();
    }

    @Override
    public ApiResponse<Void> urgeConfirm() {
        Long userId = ShiroUtil.getUserId();
        update(new UpdateWrapper<SysFruit>()
                .eq("user_id",userId)
                .set("is_urge",false)
        );
        return new ApiResponse<>();
    }

    @Override
    public ApiResponse<Void> fruitUrge(FruitUrgePO po) {
        List<Long> fruitList = po.getFruitList();
        if(fruitList==null||fruitList.size()<1){
            return new ApiResponse<>();
        }
        update(new LambdaUpdateWrapper<SysFruit>()
                .in(SysFruit::getId,fruitList)
                .set(SysFruit::getIsUrge,true)
        );
        return new ApiResponse<>();
    }

    /**
     * 周结果每周日晚上59分59秒
     */
//    @Scheduled(cron="59 59 23 ? * SUN")
    public void WeekResultTask() {
        //扣除水果机金的总集合
        List<SysFruit> fruitList = new ArrayList<>();
        Set<Long> userIds = sysUserService.userAll().stream().map(UserListVO::getUserId).collect(Collectors.toSet());
        Map<Long, List<String>> userRoles = sysUserMapper.userRoleByUserIds(userIds).stream().collect(Collectors.toMap(UserRoleDTO::getUserId, UserRoleDTO::getRoleNames));
        DateTime yesterday = DateTime.now();
        Instant yesterdayInstant = yesterday.toInstant(); ZoneId yesterdayZoneId = ZoneId.systemDefault();
        LocalDateTime yesterdayLocalDateTime = LocalDateTime.ofInstant(yesterdayInstant, yesterdayZoneId);
        //查询上周所在的周的id
        SysWeekTime sysWeekTimeServiceOne = sysWeekTimeService.getOne(new LambdaQueryWrapper<SysWeekTime>()
                .le( SysWeekTime::getBeginTime, yesterdayLocalDateTime)
                .ge( SysWeekTime::getEndTime, yesterdayLocalDateTime));
        if (sysWeekTimeServiceOne==null){
            return;
        }
        //只要是员工，都要交周报
        fruitList.addAll(userIds.stream().filter(k->DailyShiroUtil.isStaff(userRoles.get(k)))
                .filter(k->sysWeekResultService.count(new LambdaQueryWrapper<SysWeekResult>()
                        .eq(SysWeekResult::getWeekId, sysWeekTimeServiceOne.getId())
                        .eq(SysWeekResult::getUserId,k)) < 1)
                .map(k->new SysFruit(k, "周结果超时未交", SysConfigEnum.WEEK_RESULT_DEFAULT_ADD_FRUIT.getValue().doubleValue())).collect(Collectors.toList()));
        saveBatch(fruitList);
    }


    /**
     * 周计划 每周日晚上59：59生成
     */
//    @Scheduled(cron="59 59 23 ? * SUN")
    public void WeekPlanTask() {
        List<SysFruit> fruitList = new ArrayList<>();
        Set<Long> userIds = sysUserService.userAll().stream().map(UserListVO::getUserId).collect(Collectors.toSet());
        Map<Long, List<String>> userRoles = sysUserMapper.userRoleByUserIds(userIds).stream().collect(Collectors.toMap(UserRoleDTO::getUserId, UserRoleDTO::getRoleNames));
        //扣除水果机金的总集合
        DateTime nextWeek = DateUtil.nextWeek();
        Instant nextWeekInstant = nextWeek.toInstant(); ZoneId nextWeekZoneId = ZoneId.systemDefault();
        LocalDateTime nextWeekLocalDateTime = LocalDateTime.ofInstant(nextWeekInstant, nextWeekZoneId);
        //判断下周的周的id
        SysWeekTime sysWeekTimeServiceOne = sysWeekTimeService.getOne(new LambdaQueryWrapper<SysWeekTime>()
                .le( SysWeekTime::getBeginTime, nextWeekLocalDateTime)
                .ge( SysWeekTime::getEndTime, nextWeekLocalDateTime));
        if (sysWeekTimeServiceOne==null){
            return;
        }
        //只要是员工，都要交周报
        fruitList.addAll(userIds.stream().filter(k->DailyShiroUtil.isStaff(userRoles.get(k)))
                .filter(k->sysWeekResultService.count(new LambdaQueryWrapper<SysWeekResult>()
                        .eq(SysWeekResult::getWeekId, sysWeekTimeServiceOne.getId())
                        .eq(SysWeekResult::getUserId,k)) < 1)
                .map(k->new SysFruit(k, "周计划超时未交", SysConfigEnum.WEEK_PLAN_DEFAULT_ADD_FRUIT.getValue().doubleValue())).collect(Collectors.toList()));
        saveBatch(fruitList);
    }

    /**
     * ok 超时处理 整点的 延后5s
     */
    @Scheduled(cron = "5 0 0/1 * * ?")
    public void okFormCheck() {
        LocalDateTime now = LocalDateTime.now();
        List<SysOkForm> okFormList = sysOkFormService.list(
                new LambdaQueryWrapper<SysOkForm>()
                        .lt(SysOkForm::getCompleteDate, now)
                        .eq(SysOkForm::getStatus, ConstUtil.OK_FORM_NORMAL)
        );
        // 状态修改为超时
        okFormList.forEach(sysOkForm -> sysOkForm.setStatus(ConstUtil.OK_FORM_OVERTIME));
        List<SysFruit> okFromFruits = okFormList
                .stream()
                .map(k ->
                        new SysFruit(k.getLiablerId(), "ok单超时", SysConfigEnum.DEFAULT_ADD_FRUIT.getValue().doubleValue()
                        ))
                .collect(Collectors.toList());
        sysOkFormService.updateBatchById(okFormList);
        saveBatch(okFromFruits);
        log.info("ok 单 超时处理成功");
    }

    /**
     * 日报检测
     * 每日在第二天的0：0：5秒检测
     */
    @Scheduled(cron = "5 * * * * *")
    public void dailyCheck() {
        LocalDate today = LocalDate.now();
        LocalDate now=today.minusDays(1);
        SysCalendar deductDate = sysCalendarService.getOne(new LambdaQueryWrapper<SysCalendar>().eq(SysCalendar::getSelectedDate, now));

        Set<Long> userIds = sysUserService.userAll().stream().map(UserListVO::getUserId).collect(Collectors.toSet());
        Map<Long, List<String>> userRoles = sysUserMapper.userRoleByUserIds(userIds).stream().collect(Collectors.toMap(UserRoleDTO::getUserId, UserRoleDTO::getRoleNames));
        //扣除水果机金的总集合
        List<SysFruit> fruitList = new ArrayList<>();
        //判断今天是不是需要扣钱（需要提交日报等）,如果数据库没有，或者有但是不需要缴纳.1需要缴纳，0不需要缴纳
        //只要是员工，都要交日报.
        if(deductDate==null||deductDate.getDeductMoney()){
            fruitList.addAll(userIds.stream().filter(k->DailyShiroUtil.isStaff(userRoles.get(k)))
                    .filter(k->sysDailyService.count(new LambdaQueryWrapper<SysDaily>()
                            .eq(SysDaily::getDailyTime, now)
                            .ne(SysDaily::getState,2)
                            .eq(SysDaily::getWorkerId, k)) < 1)
                    .map(k->new SysFruit(k, "日报未按时提交", SysConfigEnum.DAILY_DEFAULT_ADD_FRUIT.getValue().doubleValue())).collect(Collectors.toList()));

            //检查领导每日点评次数
            fruitList.addAll(userIds.stream().filter(k->DailyShiroUtil.isLead(userRoles.get(k)))
                    .filter(k->sysDailyCommentService.count(new LambdaQueryWrapper<SysDailyComment>()
                            .eq(SysDailyComment::getCommentDate,now).eq(SysDailyComment::getCommentUserId,k))<SysConfigEnum.LEAST_COMMENT_TIMES.getValue())
                    .map(k->new SysFruit(k, "每日点评次数不够", SysConfigEnum.DEFAULT_ADD_FRUIT.getValue().doubleValue())).collect(Collectors.toList()));

        }


        //谁没回复领导的评论
        List<SysDailyComment> dailyCommentList = sysDailyCommentService.list(
                new LambdaQueryWrapper<SysDailyComment>()
                        .eq(SysDailyComment::getCommentDate,now.minusDays(1))
                        .eq(SysDailyComment::getNeedReply, true)
                        .eq(SysDailyComment::getIsReply, false));
        fruitList.addAll(dailyCommentList.stream()
                .map(k->new SysFruit(k.getDailyWorkerId(),"未及时回复领导评论",SysConfigEnum.DEFAULT_ADD_FRUIT.getValue().doubleValue()))
                .collect(Collectors.toList()));
        System.out.println(fruitList);
        saveBatch(fruitList);
    }
}
